package com.duojuhe.coremodule.chat.im.service.impl;

import com.alibaba.fastjson.JSON;
import com.duojuhe.common.file.service.FileUploadHandler;
import com.duojuhe.common.utils.file.UploadFileBean;
import com.duojuhe.coremodule.chat.im.entity.*;
import com.duojuhe.coremodule.chat.im.handle.ChatBuildMessageUtils;
import com.duojuhe.coremodule.chat.im.handle.ChatHandleCommonKit;
import com.duojuhe.coremodule.chat.im.mapper.*;
import com.duojuhe.coremodule.chat.im.pojo.dto.talkrecord.*;
import com.duojuhe.coremodule.chat.im.pojo.dto.talkrecord.forward.QueryChatTalkRecordForwardPageReq;
import com.duojuhe.coremodule.chat.im.pojo.dto.talkrecord.forward.QueryChatTalkRecordForwardPageRes;
import com.duojuhe.coremodule.chat.im.pojo.dto.talkrecord.sendtalk.*;
import com.duojuhe.websocket.subscriber.message.talk.bean.VoteRes;
import com.duojuhe.websocket.subscriber.message.talk.bean.vote.AnswerOptionRes;
import com.duojuhe.coremodule.chat.im.service.ChatTalkRecordService;
import com.duojuhe.websocket.EventCodes;
import com.duojuhe.websocket.subscriber.SubscribeHandleDto;
import com.duojuhe.websocket.subscriber.message.delete.DeleteTalkMessageDto;
import com.duojuhe.websocket.subscriber.message.revoke.RevokeTalkMessageDto;
import com.duojuhe.websocket.subscriber.message.talk.bean.CodeBlockRes;
import com.duojuhe.websocket.subscriber.message.talk.bean.FileRes;
import com.duojuhe.websocket.subscriber.message.talk.MessageBodyRes;
import com.duojuhe.websocket.subscriber.message.talk.bean.vote.DetailRes;
import com.duojuhe.websocket.subscriber.message.talk.bean.vote.StatisticsRes;
import com.duojuhe.common.annotation.KeyLock;
import com.duojuhe.common.bean.UserTokenInfoVo;
import com.duojuhe.common.config.FileUploadConfig;
import com.duojuhe.common.constant.SingleStringConstant;
import com.duojuhe.common.enums.chat.ImChatEnum;
import com.duojuhe.common.exception.base.DuoJuHeException;
import com.duojuhe.common.file.entity.FileSplitUpload;
import com.duojuhe.common.file.mapper.FileSplitUploadMapper;
import com.duojuhe.common.result.ErrorCodes;
import com.duojuhe.common.result.PageResult;
import com.duojuhe.common.result.ServiceResult;
import com.duojuhe.common.utils.dateutils.DateUtils;
import com.duojuhe.common.utils.encryption.md5.MD5Util;
import com.duojuhe.common.utils.file.MimeTypeUtils;
import com.duojuhe.common.utils.file.UploadFileUtil;
import com.duojuhe.common.utils.page.PageHelperUtil;
import com.duojuhe.coremodule.BaseService;
import com.duojuhe.coremodule.system.entity.SystemUser;
import com.duojuhe.coremodule.system.mapper.SystemUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ChatTalkRecordServiceImpl extends BaseService implements ChatTalkRecordService {
    @Resource
    private ChatHandleCommonKit chatHandleCommonKit;
    @Resource
    private FileUploadConfig fileUploadConfig;
    @Resource
    private ChatTalkRecordMapper chatTalkRecordMapper;
    @Resource
    private ChatEmoticonItemMapper chatEmoticonItemMapper;
    @Resource
    private ChatGroupUserMapper chatGroupUserMapper;
    @Resource
    private ChatTalkRecordFileMapper chatTalkRecordFileMapper;
    @Resource
    private ChatTalkRecordCodeMapper chatTalkRecordCodeMapper;
    @Resource
    private SystemUserMapper systemUserMapper;
    @Resource
    private ChatTalkRecordDeleteMapper chatTalkRecordDeleteMapper;
    @Resource
    private ChatTalkRecordVoteMapper chatTalkRecordVoteMapper;
    @Resource
    private ChatTalkRecordVoteAnswerMapper chatTalkRecordVoteAnswerMapper;
    @Resource
    private ChatTalkRecordForwardMapper chatTalkRecordForwardMapper;
    @Resource
    private FileSplitUploadMapper fileSplitUploadMapper;
    @Resource
    private FileUploadHandler fileUploadHandler;
    /**
     *【查询用户聊天记录】分页查询查询用户聊天记录
     * @param req
     * @return
     */
    @Override
    public ServiceResult<PageResult<List<QueryChatTalkRecordPageRes>>> queryChatTalkRecordPageResList(QueryChatTalkRecordPageReq req) {
        //当前用户id
        String userId = getCurrentLoginUserId();
        //校验查询参数
        Date recordEndTime = chatHandleCommonKit.getQueryChatTalkRecordEndTime(userId,req.getTalkType(),req.getReceiverId());
        //查询排序
        PageHelperUtil.orderByAndStartPage(req, "releaseTime desc,createTime desc, recordId desc");
        List<QueryChatTalkRecordPageRes> list = chatTalkRecordMapper.queryChatTalkRecordPageResList(req,userId,recordEndTime);
        for (QueryChatTalkRecordPageRes res:list){
            chatHandleCommonKit.handleChatTalkRecord(res);
        }
        return PageHelperUtil.returnServiceResult(req,list);
    }

    /**
     *【查找用户聊天记录服务接口】查找用户聊天记录服务接口
     * @param req
     * @return
     */
    @Override
    public ServiceResult<PageResult<List<QueryChatTalkRecordPageRes>>> findChatTalkRecordPageResList(QueryChatTalkRecordPageReq req) {
        //当前用户id
        String userId = getCurrentLoginUserId();
        //校验查询参数
        Date recordEndTime = chatHandleCommonKit.getQueryChatTalkRecordEndTime(userId,req.getTalkType(),req.getReceiverId());
        //查询排序
        PageHelperUtil.orderByAndStartPage(req, "releaseTime desc,createTime desc, recordId desc");
        List<QueryChatTalkRecordPageRes> list = chatTalkRecordMapper.findChatTalkRecordPageResList(req,userId,recordEndTime);
        for (QueryChatTalkRecordPageRes res:list){
            chatHandleCommonKit.handleChatTalkRecord(res);
        }
        return PageHelperUtil.returnServiceResult(req,list);
    }

    /**
     *【获取转发会话记录详情列表服务接口】获取转发会话记录详情列表服务接口
     * @param req
     * @return
     */
    @Override
    public ServiceResult<PageResult<List<QueryChatTalkRecordForwardPageRes>>> queryChatTalkRecordForwardPageResList(QueryChatTalkRecordForwardPageReq req) {
        String recordId = req.getRecordId();
        ChatTalkRecord record = chatTalkRecordMapper.selectByPrimaryKey(recordId);
        if (record==null||ImChatEnum.IM_YES_NO.YES.getKey().equals(record.getIsRevoke())){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        if (!ImChatEnum.TalkMessageType.FORWARD_MESSAGE.getKey().equals(record.getMsgType())){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        ChatTalkRecordForward forward = chatTalkRecordForwardMapper.selectByPrimaryKey(recordId);
        if (forward==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        String forwardRecordIds = forward.getForwardRecordIds();
        if (StringUtils.isBlank(forwardRecordIds)){
            return PageHelperUtil.returnServiceResult(req,new ArrayList<>());
        }
        List<String> recordIdList = Arrays.asList(forwardRecordIds.split(SingleStringConstant.COMMA));
        //查询排序
        PageHelperUtil.orderByAndStartPage(req, "releaseTime desc,createTime desc, recordId desc");
        List<QueryChatTalkRecordPageRes> list = chatTalkRecordMapper.queryChatTalkRecordForwardPageResListByRecordIdList(recordIdList);
        for (QueryChatTalkRecordPageRes res:list){
            chatHandleCommonKit.handleChatTalkRecord(res);
        }
        return PageHelperUtil.returnServiceResult(req,list);
    }

    /**
     * 发送代码块消息服务接口 发送代码块消息服务接口
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult sendTalkCodeBlock(SendTalkCodeBlockReq req) {
        //消息类型
        Integer msgType = ImChatEnum.TalkMessageType.CODE_MESSAGE.getKey();
        //查询发送者信息
        SystemUser systemUser = systemUserMapper.selectByPrimaryKey(getCurrentLoginUserId());
        if (systemUser==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //构建消息记录
        ChatTalkRecord record = chatHandleCommonKit.buildChatTalkRecord(msgType,req,systemUser);
        record.setContent(req.getCode());
        //构建代码片段关系记录
        ChatTalkRecordCode recordCode = new ChatTalkRecordCode();
        recordCode.setCodeId(record.getRecordId());
        recordCode.setRecordId(record.getRecordId());
        recordCode.setIsDelete(ImChatEnum.IM_YES_NO.NO.getKey());
        recordCode.setUserId(record.getUserId());
        recordCode.setCreateUserId(record.getCreateUserId());
        recordCode.setCreateTime(record.getCreateTime());
        recordCode.setCodeLang(req.getLang());
        recordCode.setCodeContent(req.getCode());
        //保存消息记录
        chatTalkRecordMapper.insertSelective(record);
        //保存文件
        chatTalkRecordCodeMapper.insertSelective(recordCode);
        //发送消息
        MessageBodyRes bodyRes = ChatBuildMessageUtils.buildMessageBodyRes(record);
        bodyRes.setCodeBlock(new CodeBlockRes(recordCode));
        //保存最后的消息记录
        chatHandleCommonKit.handleLastMessage(record);
        //发送消息到各个订阅端
        chatHandleCommonKit.handleSendChatSubscribe(bodyRes);
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }



    /**
     * 发送聊天文件服务接口
     * @param req
     * @return
     */
    @KeyLock(lockKeyParts = "hashName")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult sendTalkFile(SendTalkFileReq req) throws Exception {
        //当前用户
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //当前用户id
        String userId = userTokenInfoVo.getUserId();
        //当前用户编号
        String userNumber = userTokenInfoVo.getUserNumber();
        //系统文件名
        FileSplitUpload splitUploadOld = fileSplitUploadMapper.selectByPrimaryKey(req.getHashName());
        if (splitUploadOld==null || !userId.equals(splitUploadOld.getUserId())){
            return ServiceResult.fail(ErrorCodes.UPLOAD_FILE_NOT_FOUND);
        }
        int byteSize = Integer.parseInt(String.valueOf(splitUploadOld.getFileSize()));
        byte[] fileBytes = new byte[byteSize];
        int begin = 0;
        for (FileSplitUpload upload:fileSplitUploadMapper.queryFileSplitUploadListByParentId(splitUploadOld.getUploadId())){
            byte[] fileContent = upload.getFileContent();
            System.arraycopy(fileContent, 0, fileBytes, begin, fileContent.length);
            begin += fileContent.length;
        }
        //文件名称
        String originalFilename = splitUploadOld.getOriginalName();
        InputStream inputStream = new ByteArrayInputStream(fileBytes);
        MultipartFile file = new MockMultipartFile(ContentType.APPLICATION_OCTET_STREAM.toString(),originalFilename,null, inputStream);
        // 判断文件大小
        long fileSize = file.getSize();
        long maxFileSize = fileUploadConfig.getMaxSize(fileUploadConfig.getMaxFileSize());
        if (fileSize > maxFileSize) {
            return ServiceResult.fail(ErrorCodes.UPLOAD_FILE_TOO_LARGE);
        }
        //查询发送者信息
        SystemUser systemUser = systemUserMapper.selectByPrimaryKey(getCurrentLoginUserId());
        if (systemUser==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //用户聊天目录dir
        String chatTalkDir = File.separator+"chatTalkFile"+File.separator+userNumber;
        //文件根目录
        String rootPath = fileUploadConfig.getRootPath()+chatTalkDir;
        //文件前缀
        String fileUrlPrefix = fileUploadConfig.getFileUrlPrefix()+chatTalkDir;
        //附件上传前缀域名
        String filePrefixDomain = fileUploadConfig.getFilePrefixDomain();
        //允许文件类型
        String[] allowFiles = fileUploadConfig.getFileAllowFiles();
        //构建文件上传对象
        UploadFileBean uploadFileBean = UploadFileUtil.writeSingleFileToDisk(file,allowFiles,filePrefixDomain, rootPath, fileUrlPrefix);
        //请求路径
        String fileUrl = uploadFileBean.getFileAbsolutePath();
        if (StringUtils.isBlank(fileUrl)) {
            return ServiceResult.fail(ErrorCodes.UPLOAD_FILE_FORMAT_ERROR);
        }
        //保存文件到文件库
        fileUploadHandler.addNewFileUpload(uploadFileBean,userTokenInfoVo);

        //文件后缀
        String fileSuffix = UploadFileUtil.getFileSuffix(file);
        //文件名称
        String originalName = file.getOriginalFilename();
        //消息类型
        Integer msgType = ImChatEnum.TalkMessageType.FILE_MESSAGE.getKey();
        //文件类型
        Integer fileType = getMediaType(fileSuffix);
        //构建消息记录
        ChatTalkRecord record = chatHandleCommonKit.buildChatTalkRecord(msgType,req,systemUser);
        record.setFileType(fileType);
        record.setContent(originalName);
        //构建文件关系记录
        ChatTalkRecordFile chatTalkRecordFile = new ChatTalkRecordFile();
        chatTalkRecordFile.setFileId(record.getRecordId());
        chatTalkRecordFile.setRecordId(record.getRecordId());
        chatTalkRecordFile.setUserId(record.getUserId());
        chatTalkRecordFile.setCreateUserId(record.getCreateUserId());
        chatTalkRecordFile.setFileUrl(fileUrl);
        chatTalkRecordFile.setFileType(fileType);
        chatTalkRecordFile.setOriginalName(originalName);
        chatTalkRecordFile.setFileSuffix(fileSuffix);
        chatTalkRecordFile.setFileSize(fileSize);
        chatTalkRecordFile.setIsDelete(record.getIsDelete());
        chatTalkRecordFile.setCreateTime(record.getCreateTime());

        //合并完了删除对应的拆分记录beg
        String uploadId = splitUploadOld.getUploadId();
        //删除拆分子记录
        FileSplitUpload deleteSplitUpload = new FileSplitUpload();
        deleteSplitUpload.setParentId(uploadId);
        fileSplitUploadMapper.delete(deleteSplitUpload);
        //删除拆分主信息记录
        fileSplitUploadMapper.deleteByPrimaryKey(uploadId);
        //合并完了删除对应的拆分记录end

        //保存消息记录
        chatTalkRecordMapper.insertSelective(record);
        //保存消息文件
        chatTalkRecordFileMapper.insertSelective(chatTalkRecordFile);
        //发送消息
        MessageBodyRes bodyRes = ChatBuildMessageUtils.buildMessageBodyRes(record);
        bodyRes.setFile(new FileRes(chatTalkRecordFile));
        //保存最后的消息记录
        chatHandleCommonKit.handleLastMessage(record);
        //发送消息到各个订阅端
        chatHandleCommonKit.handleSendChatSubscribe(bodyRes);
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }

    /**
     * 发送聊天图片服务接口 发送聊天图片服务接口
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult sendTalkImage(MultipartFile file,SendTalkImageReq req) {
        if (file==null||file.isEmpty()){
            return ServiceResult.fail(ErrorCodes.UPLOAD_FILE_NOT_FOUND);
        }
        // 判断文件大小
        long fileSize = file.getSize();
        long maxImageSize = fileUploadConfig.getMaxSize(fileUploadConfig.getMaxImageSize());
        if (fileSize > maxImageSize) {
            return ServiceResult.fail(ErrorCodes.UPLOAD_FILE_TOO_LARGE);
        }
        //查询发送者信息
        SystemUser systemUser = systemUserMapper.selectByPrimaryKey(getCurrentLoginUserId());
        if (systemUser==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //用户编号
        String userNumber = systemUser.getUserNumber();
        //用户聊天目录dir
        String chatTalkDir = File.separator+"chatTalkImage"+File.separator+userNumber;
        //文件根目录
        String rootPath = fileUploadConfig.getRootPath()+chatTalkDir;
        //文件前缀
        String imageUrlPrefix = fileUploadConfig.getFileUrlPrefix()+chatTalkDir;
        //附件上传前缀域名
        String filePrefixDomain = fileUploadConfig.getFilePrefixDomain();
        //允许图片文件类型
        String[] allowFiles = fileUploadConfig.getImageAllowFiles();
        //开始上传
        UploadFileBean uploadFileBean = UploadFileUtil.writeSingleImageToDisk(file,allowFiles,filePrefixDomain, rootPath, imageUrlPrefix);
        //请求路径
        String fileAbsolutePath = uploadFileBean.getFileAbsolutePath();
        if (StringUtils.isBlank(fileAbsolutePath)) {
            return ServiceResult.fail(ErrorCodes.UPLOAD_FILE_FORMAT_ERROR);
        }
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //保存文件到文件库
        fileUploadHandler.addNewFileUpload(uploadFileBean,userTokenInfoVo);
        //文件后缀
        String fileSuffix = UploadFileUtil.getFileSuffix(file);
        //文件名称
        String originalName = file.getOriginalFilename();
        //消息类型
        Integer msgType = ImChatEnum.TalkMessageType.FILE_MESSAGE.getKey();

        //文件类型
        Integer fileType = ImChatEnum.FileType.FILE_IMAGE.getKey();
        //构建消息记录
        ChatTalkRecord record = chatHandleCommonKit.buildChatTalkRecord(msgType,req,systemUser);
        record.setFileType(fileType);
        record.setContent(originalName);
        //构建文件关系记录
        ChatTalkRecordFile chatTalkRecordFile = new ChatTalkRecordFile();
        chatTalkRecordFile.setFileId(record.getRecordId());
        chatTalkRecordFile.setRecordId(record.getRecordId());
        chatTalkRecordFile.setUserId(record.getUserId());
        chatTalkRecordFile.setCreateUserId(record.getCreateUserId());
        chatTalkRecordFile.setFileUrl(fileAbsolutePath);
        chatTalkRecordFile.setFileType(fileType);
        chatTalkRecordFile.setOriginalName(originalName);
        chatTalkRecordFile.setFileSuffix(fileSuffix);
        chatTalkRecordFile.setFileSize(fileSize);
        chatTalkRecordFile.setIsDelete(record.getIsDelete());
        chatTalkRecordFile.setCreateTime(record.getCreateTime());
        //保存消息记录
        chatTalkRecordMapper.insertSelective(record);

        //保存文件
        chatTalkRecordFileMapper.insertSelective(chatTalkRecordFile);
        //发送消息
        MessageBodyRes bodyRes = ChatBuildMessageUtils.buildMessageBodyRes(record);
        bodyRes.setFile(new FileRes(chatTalkRecordFile));
        //保存最后的消息记录
        chatHandleCommonKit.handleLastMessage(record);
        //发送消息到各个订阅端
        chatHandleCommonKit.handleSendChatSubscribe(bodyRes);
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }




    /**
     * 发送表情包服务接口
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult sendTalkEmoticon(SendTalkEmoticonReq req) {
        //查询表情记录
        ChatEmoticonItem emoticonItem = chatEmoticonItemMapper.selectByPrimaryKey(req.getEmoticonId());
        if (emoticonItem==null){
            return ServiceResult.fail(ErrorCodes.EMOTICON_ITEM_NOT_FOUND);
        }
        //消息类型
        Integer msgType = ImChatEnum.TalkMessageType.FILE_MESSAGE.getKey();
        //查询发送者信息
        SystemUser systemUser = systemUserMapper.selectByPrimaryKey(getCurrentLoginUserId());
        if (systemUser==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //构建消息记录
        ChatTalkRecord record = chatHandleCommonKit.buildChatTalkRecord(msgType,req,systemUser);
        record.setFileType(emoticonItem.getFileType());
        record.setContent(emoticonItem.getOriginalName());
        //构建文件关系记录
        ChatTalkRecordFile chatTalkRecordFile = new ChatTalkRecordFile();
        chatTalkRecordFile.setFileId(record.getRecordId());
        chatTalkRecordFile.setRecordId(record.getRecordId());
        chatTalkRecordFile.setUserId(record.getUserId());
        chatTalkRecordFile.setCreateUserId(record.getCreateUserId());
        chatTalkRecordFile.setFileUrl(emoticonItem.getEmoticonUrl());
        chatTalkRecordFile.setFileType(emoticonItem.getFileType());
        chatTalkRecordFile.setOriginalName(emoticonItem.getOriginalName());
        chatTalkRecordFile.setFileSuffix(emoticonItem.getFileSuffix());
        chatTalkRecordFile.setFileSize(emoticonItem.getFileSize());
        chatTalkRecordFile.setIsDelete(record.getIsDelete());
        chatTalkRecordFile.setCreateTime(record.getCreateTime());
        //保存消息记录
        chatTalkRecordMapper.insertSelective(record);
        //保存文件
        chatTalkRecordFileMapper.insertSelective(chatTalkRecordFile);
        //发送消息
        MessageBodyRes bodyRes = ChatBuildMessageUtils.buildMessageBodyRes(record);
        bodyRes.setFile(new FileRes(chatTalkRecordFile));
        //保存最后的消息记录
        chatHandleCommonKit.handleLastMessage(record);
        //发送消息到各个订阅端
        chatHandleCommonKit.handleSendChatSubscribe(bodyRes);
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }

    /**
     * 转发消息服务接口
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult forwardTalkRecord(ForwardTalkRecordReq req) {
        try {
            //当前用户id
            String userId = getCurrentLoginUserId();
            //查询发送者信息
            SystemUser systemUser = systemUserMapper.selectByPrimaryKey(userId);
            if (systemUser==null){
                return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
            }
            //校验并获得返回值
            List<SendTalkReq> sendTalkReqList = chatHandleCommonKit.verifyForward(userId,req);
            //查询消息
            List<ChatTalkRecord> recordList = chatTalkRecordMapper.queryChatTalkRecordListByRecordIdList(req.getRecordIdList());
            //消息类型（只允许下列类型消息可以转发）
            Integer text = ImChatEnum.TalkMessageType.TEXT_MESSAGE.getKey();
            Integer file = ImChatEnum.TalkMessageType.FILE_MESSAGE.getKey();
            Integer code = ImChatEnum.TalkMessageType.CODE_MESSAGE.getKey();
            //是否标识
            Integer no = ImChatEnum.IM_YES_NO.NO.getKey();
            //过滤出允许转发的消息出来
            List<ChatTalkRecord> talkRecordList = recordList.stream().filter(e->(text.equals(e.getMsgType())||
                    file.equals(e.getMsgType())||code.equals(e.getMsgType()))&&no.equals(e.getIsRevoke())).collect(Collectors.toList());
            if (req.getRecordIdList().size()!=talkRecordList.size()){
                return ServiceResult.fail("选择的转发消息存在不可转发记录，请重新选择!");
            }
            //转发方式
            Integer oneForward = ImChatEnum.ForwardMode.ONE_FORWARD.getKey();
            //分割逐条转发
            if (oneForward.equals(req.getForwardMode())){
                return chatHandleCommonKit.multiSplitForward(systemUser,talkRecordList,sendTalkReqList);
            }
            //合并转发
            return chatHandleCommonKit.multiMergeForward(systemUser,talkRecordList,sendTalkReqList);
        }catch (Exception e){
            throw new DuoJuHeException("转发失败!");
        }
    }

    /**
     * 发送投票服务接口
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult sendTalkVote(SendTalkVoteReq req) {
        if (!ImChatEnum.TalkType.GROUP_CHAT.getKey().equals(req.getTalkType())){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //消息类型
        Integer msgType = ImChatEnum.TalkMessageType.VOTE_MESSAGE.getKey();
        //查询发送者信息
        SystemUser systemUser = systemUserMapper.selectByPrimaryKey(getCurrentLoginUserId());
        if (systemUser==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //当前登录人用户id
        String userId = systemUser.getUserId();
        //主键ID 当前用户id和接收id的MD5值
        String id = MD5Util.getMD532(userId+req.getReceiverId());
        ChatGroupUser groupUser = chatGroupUserMapper.selectByPrimaryKey(id);
        if (groupUser==null){
            return ServiceResult.fail(ErrorCodes.NOT_GROUP_USER_NO_TALK_ERROR);
        }
        //构建消息记录
        ChatTalkRecord record = chatHandleCommonKit.buildChatTalkRecord(msgType,req,systemUser);
        record.setContent(req.getVoteTitle());

        //答题选项内容
        List<String> answerOptionList = req.getAnswerOptionList();
        //选项
        List<AnswerOptionRes> optionList = new ArrayList<>();
        //统计
        Map<String,Integer> statisticsResMap = new HashMap<>();
        for(int i=0;i<answerOptionList.size();i++){
            String key = ""+(char)(65+i);
            String value = answerOptionList.get(i);
            //选项
            AnswerOptionRes optionRes = new AnswerOptionRes();
            optionRes.setKey(key);
            optionRes.setValue(value);
            optionList.add(optionRes);
            //统计
            statisticsResMap.put(key,0);
        }
        //答题选项
        String answerOption = optionList.stream().map(AnswerOptionRes::getKey).collect(Collectors.joining(SingleStringConstant.COMMA));
        //群组id
        String groupId = req.getReceiverId();
        List<ChatGroupUser> chatGroupUserList = chatGroupUserMapper.queryChatGroupUserListByGroupId(groupId);
        //参与答题人数
        Integer answerNum = chatGroupUserList.size();
        //构建投票插入对象
        ChatTalkRecordVote talkRecordVote = new ChatTalkRecordVote();
        talkRecordVote.setVoteId(record.getRecordId());
        talkRecordVote.setRecordId(record.getRecordId());
        talkRecordVote.setUserId(record.getUserId());
        talkRecordVote.setCreateUserId(record.getCreateUserId());
        talkRecordVote.setCreateTime(record.getCreateTime());
        talkRecordVote.setUpdateTime(record.getUpdateTime());
        talkRecordVote.setVoteTitle(req.getVoteTitle());
        talkRecordVote.setAnswerMode(req.getAnswerMode());
        talkRecordVote.setAnswerNum(answerNum);
        talkRecordVote.setAnsweredNum(0);
        talkRecordVote.setVoteStatus(ImChatEnum.VoteStatus.IN_VOTING.getKey());
        talkRecordVote.setAnswerOption(answerOption);
        talkRecordVote.setAnswerOptionContent(JSON.toJSONString(optionList));
        //保存消息记录
        chatTalkRecordMapper.insertSelective(record);
        //保存投票信息
        chatTalkRecordVoteMapper.insertSelective(talkRecordVote);
        //发送消息
        //投票统计
        StatisticsRes statisticsRes = new StatisticsRes();
        statisticsRes.setCount(0);
        statisticsRes.setOptions(statisticsResMap);
        //投票详情
        DetailRes detailRes = new DetailRes();
        detailRes.setId(talkRecordVote.getVoteId());
        detailRes.setAnswerNum(talkRecordVote.getAnswerNum());
        detailRes.setAnsweredNum(talkRecordVote.getAnsweredNum());
        detailRes.setTitle(talkRecordVote.getVoteTitle());
        detailRes.setStatus(talkRecordVote.getVoteStatus());
        detailRes.setAnswerMode(talkRecordVote.getAnswerMode());
        detailRes.setAnswerOptionList(optionList);
        VoteRes voteRes = new VoteRes();
        voteRes.setStatistics(statisticsRes);
        voteRes.setDetail(detailRes);
        voteRes.setVoteUsers(new ArrayList<>());
        //构建发送消息
        MessageBodyRes bodyRes = ChatBuildMessageUtils.buildMessageBodyRes(record);
        bodyRes.setVote(voteRes);
        //保存最后的消息记录
        chatHandleCommonKit.handleLastMessage(record);
        //发送消息到各个订阅端
        chatHandleCommonKit.handleSendChatSubscribe(bodyRes);
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }


    /**
     * 提交投票服务接口
     * @param req
     * @return
     */
    @KeyLock(lockKeyParts = "recordId")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult confirmSubmitTalkVote(ConfirmSubmitTalkVoteReq req) {
        String recordId = req.getRecordId();
        ChatTalkRecord record = chatTalkRecordMapper.selectByPrimaryKey(recordId);
        if (record==null||ImChatEnum.IM_YES_NO.YES.getKey().equals(record.getIsRevoke())){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //消息类型
        Integer msgType = ImChatEnum.TalkMessageType.VOTE_MESSAGE.getKey();
        if (!msgType.equals(record.getMsgType())){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //查询投票内容
        ChatTalkRecordVote talkRecordVote = chatTalkRecordVoteMapper.selectByPrimaryKey(recordId);
        if (talkRecordVote==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //投票选项key
        String answerOption = talkRecordVote.getAnswerOption();
        if (StringUtils.isBlank(answerOption)){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //前端提交的回答
        List<String> answerList = req.getAnswerList();
        if (answerList.size()!=new HashSet<>(req.getAnswerList()).size()){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //应答人数
        Integer answerNum = talkRecordVote.getAnswerNum();
        //已答人数
        Integer answeredNum = talkRecordVote.getAnsweredNum();
        if (answeredNum>=answerNum){
            return ServiceResult.fail("投票人数已满，禁止投票!");
        }
        //投票模式
        Integer answerMode = talkRecordVote.getAnswerMode();
        if (ImChatEnum.VoteAnswerMode.VOTING_SINGLE.getKey().equals(answerMode)&&answerList.size()!=1){
            //如果是单选模式，回答结果必须只能有一个
            return ServiceResult.fail("单选投票只能投一项，请重新投票!");
        }
        //当前登录人用户id
        String userId = getCurrentLoginUserId();
        //主键ID 当前用户id和接收id的MD5值
        String id = MD5Util.getMD532(userId+record.getReceiverId());
        ChatGroupUser groupUser = chatGroupUserMapper.selectByPrimaryKey(id);
        if (groupUser==null){
            return ServiceResult.fail(ErrorCodes.NOT_GROUP_USER_NO_TALK_ERROR);
        }
        //答题ID
        String answerId = MD5Util.getMD532(userId+recordId);
        //判断是否回答过了
        if (chatTalkRecordVoteAnswerMapper.selectByPrimaryKey(answerId)!=null){
            return ServiceResult.fail("请勿重复投票!");
        }
        List<String> answerOptionList = Arrays.asList(answerOption.split(SingleStringConstant.COMMA));
        //判断回答选项是否都在范围内
        for (String answer:answerList){
            if (!answerOptionList.contains(answer)){
                throw new DuoJuHeException(ErrorCodes.PARAM_ERROR);
            }
        }
        //回答值
        String answerString= String.join(SingleStringConstant.COMMA, answerList);
        //当前时间
        Date nowDate = new Date();
        ChatTalkRecordVoteAnswer voteAnswer = new ChatTalkRecordVoteAnswer();
        voteAnswer.setAnswerId(answerId);
        voteAnswer.setVoteId(talkRecordVote.getVoteId());
        voteAnswer.setUserId(userId);
        voteAnswer.setCreateTime(nowDate);
        voteAnswer.setAnswerOption(answerString);
        //插入
        chatTalkRecordVoteAnswerMapper.insertSelective(voteAnswer);
        //更新投票信息
        //投票中
        Integer inVoting = ImChatEnum.VoteStatus.IN_VOTING.getKey();
        //投票完成
        Integer completed = ImChatEnum.VoteStatus.VOTING_COMPLETED.getKey();
        //新的已答数量
        Integer answeredNumNew = talkRecordVote.getAnsweredNum()+1;
        ChatTalkRecordVote updateTalkRecordVote = new ChatTalkRecordVote();
        updateTalkRecordVote.setVoteId(talkRecordVote.getVoteId());
        updateTalkRecordVote.setUpdateTime(nowDate);
        updateTalkRecordVote.setAnsweredNum(answeredNumNew);
        updateTalkRecordVote.setVoteStatus(answeredNumNew>=answerNum?completed:inVoting);
        chatTalkRecordVoteMapper.updateByPrimaryKeySelective(updateTalkRecordVote);
        return ServiceResult.ok(buildStatisticsRes(talkRecordVote));
    }

    /**
     *【根据会话id查询投票记录汇总信息】根据会话id查询投票记录汇总信息
     * @param req
     * @return
     */
    @Override
    public ServiceResult<StatisticsRes> queryChatTalkRecordVoteStatisticsResByRecordId(ChatTalkRecordIdReq req) {
        ChatTalkRecord record = chatTalkRecordMapper.selectByPrimaryKey(req.getRecordId());
        if (record==null||ImChatEnum.IM_YES_NO.YES.getKey().equals(record.getIsRevoke())){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //消息类型
        Integer msgType = ImChatEnum.TalkMessageType.VOTE_MESSAGE.getKey();
        if (!msgType.equals(record.getMsgType())){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //查询投票内容
        ChatTalkRecordVote talkRecordVote = chatTalkRecordVoteMapper.selectByPrimaryKey(record.getRecordId());
        if (talkRecordVote==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //投票选项key
        String answerOption = talkRecordVote.getAnswerOption();
        if (StringUtils.isBlank(answerOption)){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        return ServiceResult.ok(buildStatisticsRes(talkRecordVote));
    }


    /**
     * 撤回消息服务接口
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult revokeRecordByRecordId(ChatTalkRecordIdReq req) {
        String recordId = req.getRecordId();
        ChatTalkRecord record = chatTalkRecordMapper.selectByPrimaryKey(recordId);
        if (record==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //用户id
        String userId = userTokenInfoVo.getUserId();
        //是否标识
        Integer yes = ImChatEnum.IM_YES_NO.YES.getKey();
        if (!userId.equals(record.getCreateUserId()) || yes.equals(record.getIsRevoke())){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        // 判断是否在两分钟之内撤回消息，超过2分钟不能撤回消息
        if (!DateUtils.checkDateTimeWithinMinutes(record.getReleaseTime(),2)){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        record.setIsRevoke(yes);
        chatTalkRecordMapper.updateByPrimaryKeySelective(record);
        //保存最后的消息记录
        chatHandleCommonKit.handleLastMessage(record);
        //发送者id
        String senderId = record.getUserId();
        //接收对象id
        String receiverId = record.getReceiverId();
        //聊天类型
        Integer talkType = record.getTalkType();
        //发送消息
        RevokeTalkMessageDto revokeTalkMessageDto = new RevokeTalkMessageDto(talkType,senderId,receiverId,recordId);
        SubscribeHandleDto<RevokeTalkMessageDto> subscribeHandleDto = new SubscribeHandleDto();
        subscribeHandleDto.setEventType(EventCodes.EVENT_REVOKE_TALK.getEvent());
        subscribeHandleDto.setMessageData(revokeTalkMessageDto);
        chatHandleCommonKit.sendImSubscribeMessage(subscribeHandleDto);
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }

    /**
     * 删除消息服务接口
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult deleteRecordByRecordId(ChatTalkRecordIdReq req) {
        String recordId = req.getRecordId();
        ChatTalkRecord record = chatTalkRecordMapper.selectByPrimaryKey(recordId);
        if (record==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //当前用户id
        String userId = getCurrentLoginUserId();
        //删除记录id
        String deleteId = MD5Util.getMD532(userId+recordId);
        //如果已经存在了，则直接返回成功
        if (chatTalkRecordDeleteMapper.selectByPrimaryKey(deleteId)!=null){
            return ServiceResult.ok(ErrorCodes.SUCCESS);
        }
        //删除记录表
        ChatTalkRecordDelete recordDelete = new ChatTalkRecordDelete();
        recordDelete.setDeleteId(deleteId);
        recordDelete.setRecordId(recordId);
        recordDelete.setUserId(userId);
        recordDelete.setCreateUserId(userId);
        recordDelete.setCreateTime(new Date());
        chatTalkRecordDeleteMapper.insertSelective(recordDelete);
        //发送消息
        List<String> deleteIdList = new ArrayList<>();
        deleteIdList.add(recordId);
        //发送者id
        String senderId = record.getUserId();
        //接收对象id
        String receiverId = record.getReceiverId();
        //聊天类型
        Integer talkType = record.getTalkType();
        //发送消息
        DeleteTalkMessageDto deleteTalkMessageDto = new DeleteTalkMessageDto(talkType,senderId,receiverId,deleteIdList);
        SubscribeHandleDto<DeleteTalkMessageDto> subscribeHandleDto = new SubscribeHandleDto();
        subscribeHandleDto.setEventType(EventCodes.EVENT_DELETE_TALK.getEvent());
        subscribeHandleDto.setMessageData(deleteTalkMessageDto);
        chatHandleCommonKit.sendImSubscribeMessage(subscribeHandleDto);
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }


    /**
     * 批量删除消息服务接口
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult batchDeleteRecordByRecordIdList(BatchDeleteRecordIdListReq req) {
        //查询消息
        List<ChatTalkRecord> chatTalkRecordList = chatTalkRecordMapper.queryChatTalkRecordListByRecordIdList(req.getRecordIdList());
        if (req.getRecordIdList().size()!=chatTalkRecordList.size()){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //用户id
        String userId = userTokenInfoVo.getUserId();
        //当前时间
        Date nowDate = new Date();
        for (ChatTalkRecord record:chatTalkRecordList){
            //记录id
            String recordId = record.getRecordId();
            //删除记录id
            String deleteId = MD5Util.getMD532(userId+recordId);
            if (chatTalkRecordDeleteMapper.selectByPrimaryKey(deleteId)!=null){
                continue;
            }
            //删除记录表
            ChatTalkRecordDelete recordDelete = new ChatTalkRecordDelete();
            recordDelete.setDeleteId(deleteId);
            recordDelete.setRecordId(recordId);
            recordDelete.setUserId(userId);
            recordDelete.setCreateUserId(userId);
            recordDelete.setCreateTime(nowDate);
            chatTalkRecordDeleteMapper.insertSelective(recordDelete);
        }
        //接收对象id
        String receiverId = req.getReceiverId();
        //聊天类型
        Integer talkType = req.getTalkType();
        //发送消息
        DeleteTalkMessageDto deleteTalkMessageDto = new DeleteTalkMessageDto(talkType,userId,receiverId,req.getRecordIdList());
        SubscribeHandleDto<DeleteTalkMessageDto> subscribeHandleDto = new SubscribeHandleDto();
        subscribeHandleDto.setEventType(EventCodes.EVENT_DELETE_TALK.getEvent());
        subscribeHandleDto.setMessageData(deleteTalkMessageDto);
        chatHandleCommonKit.sendImSubscribeMessage(subscribeHandleDto);
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }



    /**
     * 构建投票统计返回体
     * @param talkRecordVote
     * @return
     */
    private StatisticsRes buildStatisticsRes(ChatTalkRecordVote talkRecordVote){
        //投票id
        String voteId = talkRecordVote.getVoteId();
        //投票选项key
        String answerOption = talkRecordVote.getAnswerOption();
        List<String> answerOptionList = new ArrayList<>();
        if (StringUtils.isNotBlank(answerOption)){
            answerOptionList = Arrays.asList(answerOption.split(SingleStringConstant.COMMA));
        }
        //查询投票答案信息
        List<ChatTalkRecordVoteAnswer> voteAnswerList = chatTalkRecordVoteAnswerMapper.queryChatTalkRecordVoteAnswerByVoteId(voteId);
        //回答内容体list
        List<String> answerStatisticsList =  voteAnswerList.stream().map(ChatTalkRecordVoteAnswer::getAnswerOption).collect(Collectors.toList());
        //构建结果
        Map<String,Integer> statisticsResMap = new HashMap<>();
        for(String key:answerOptionList){
            //key统计值
            Integer keyNum = 0;
            for (String answer:answerStatisticsList){
                List<String> answerArrList = Arrays.asList(answer.split(SingleStringConstant.COMMA));
                if (answerArrList.contains(key)){
                    keyNum++;
                }
            }
            //统计
            statisticsResMap.put(key,keyNum);
        }
        StatisticsRes statisticsRes = new StatisticsRes();
        statisticsRes.setCount(voteAnswerList.size());
        statisticsRes.setOptions(statisticsResMap);
        return statisticsRes;
    }


    /**
     * 根据文件后缀获取类型
     * @param prefix
     * @return
     */
    private static Integer getMediaType(String prefix) {
        if (StringUtils.isBlank(prefix)){
            return 4;
        }
        prefix = prefix.replace(SingleStringConstant.SPOT,"");
        if (Arrays.asList(MimeTypeUtils.IMAGE_EXTENSION).contains(prefix)){
            return 1;
        }else if (Arrays.asList(MimeTypeUtils.VIDEO_EXTENSION).contains(prefix)){
            return 2;
        }else if (Arrays.asList(MimeTypeUtils.MEDIA_EXTENSION).contains(prefix)){
            return 3;
        }else {
            return 4;
        }
    }

}
